home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Games / Solitaire / Sources / Pyramid / Pyramid.m < prev    next >
Text File  |  1994-04-21  |  14KB  |  479 lines

  1. /* indent:4  tabsize:8  font:fixed-width */
  2.  
  3. #import "Pyramid.h"
  4. #import "PyramidPrefs.h"
  5. #import "DiscardCardPileDelegate.h"
  6. #import "GameCardPileDelegate.h"
  7. #import "StockCardPileDelegate.h"
  8. #import "WasteCardPileDelegate.h"
  9. #import "localstrings.h"
  10.  
  11. @implementation Pyramid
  12.  
  13.  
  14.  
  15. /*---------------------------------------------------------------------------
  16. |
  17. |    - startGame:
  18. |
  19. |    returns:    (id)  self
  20. |
  21. |----------------------------------------------------------------------------
  22. |
  23. |    Start a new game.  Get confirmation from the user before aborting a 
  24. |    game in progress.
  25. |            
  26. \----------------------------------------------------------------------------*/
  27.  
  28. - startGame:sender
  29. {
  30.     if (gameInProgress) [self determineScore];
  31.     [super startGame:sender];
  32.     return [self setupGame:YES];
  33. }
  34.  
  35.  
  36. /*---------------------------------------------------------------------------
  37. |
  38. |    - restartGame:
  39. |
  40. |    returns:  (id) self
  41. |
  42. |----------------------------------------------------------------------------
  43. |
  44. |    Restart the game in progress.
  45. |            
  46. \----------------------------------------------------------------------------*/
  47.  
  48. - restartGame:sender
  49. {
  50.     if (gameInProgress) [self determineScore];
  51.     [super restartGame:sender];
  52.     return [self setupGame:NO];
  53. }
  54.  
  55.  
  56. /*---------------------------------------------------------------------------
  57. |
  58. |    - setupGame:(BOOL)redeal
  59. |
  60. |    returns:  (id) self
  61. |
  62. |----------------------------------------------------------------------------
  63. |
  64. |    Setup a new game.  If "redeal" is true, deal a new deck, otherwise
  65. |    use the same cards as the previous game.
  66. |            
  67. \----------------------------------------------------------------------------*/
  68.  
  69. - setupGame:(BOOL)redeal
  70. {
  71.     int pileIndex;
  72.     id stockCardPile = [stockCardPileView cardPile];
  73.  
  74.     [gameWindow disableFlushWindow];
  75.  
  76.     [self setDealCount:1];
  77.     pyramidEmpty = NO;
  78.     
  79.     //----------------------------------------------------------------
  80.     //    Sync pile id's with current game window and set 
  81.     //    preferences and delegates
  82.     //----------------------------------------------------------------
  83.     
  84.     gameCardPiles[0] = gamePileView1;
  85.     gameCardPiles[1] = gamePileView2;
  86.     gameCardPiles[2] = gamePileView3;
  87.     gameCardPiles[3] = gamePileView4;
  88.     gameCardPiles[4] = gamePileView5;
  89.     gameCardPiles[5] = gamePileView6;
  90.     gameCardPiles[6] = gamePileView7;
  91.     gameCardPiles[7] = gamePileView8;
  92.     gameCardPiles[8] = gamePileView9;
  93.     gameCardPiles[9] = gamePileView10;
  94.     gameCardPiles[10] = gamePileView11;
  95.     gameCardPiles[11] = gamePileView12;
  96.     gameCardPiles[12] = gamePileView13;
  97.     gameCardPiles[13] = gamePileView14;
  98.     gameCardPiles[14] = gamePileView15;
  99.     gameCardPiles[15] = gamePileView16;
  100.     gameCardPiles[16] = gamePileView17;
  101.     gameCardPiles[17] = gamePileView18;
  102.     gameCardPiles[18] = gamePileView19;
  103.     gameCardPiles[19] = gamePileView20;
  104.     gameCardPiles[20] = gamePileView21;
  105.     gameCardPiles[21] = gamePileView22;
  106.     gameCardPiles[22] = gamePileView23;
  107.     gameCardPiles[23] = gamePileView24;
  108.     gameCardPiles[24] = gamePileView25;
  109.     gameCardPiles[25] = gamePileView26;
  110.     gameCardPiles[26] = gamePileView27;
  111.     gameCardPiles[27] = gamePileView28;
  112.     
  113.     [stockCardPileView setBackgroundColor:desktopColor];
  114.     [stockCardPileView setCardSize:cardSize];
  115.     [stockCardPileView setDelegate:stockDelegate];
  116.     
  117.     [wasteCardPileView setBackgroundColor:desktopColor];
  118.     [wasteCardPileView setCardSize:cardSize];
  119.     [wasteCardPileView setDelegate:wasteDelegate];
  120.     
  121.     [discardCardPileViewL setBackgroundColor:desktopColor];
  122.     [discardCardPileViewL setCardSize:cardSize];
  123.     [discardCardPileViewL setDelegate:discardDelegate];
  124.     
  125.     [discardCardPileViewR setBackgroundColor:desktopColor];
  126.     [discardCardPileViewR setCardSize:cardSize];
  127.     [discardCardPileViewR setDelegate:discardDelegate];
  128.  
  129.     [stockDelegate setDiscardLeft:discardCardPileViewL 
  130.                      discardRight:discardCardPileViewR
  131.                     waste:wasteCardPileView];
  132.     [gameDelegate setDiscardLeft:discardCardPileViewL
  133.                     discardRight:discardCardPileViewR];
  134.     [wasteDelegate setDiscardLeft:discardCardPileViewL
  135.                     discardRight:discardCardPileViewR];
  136.      
  137.     [gameWindow display];
  138.     [gameWindow reenableFlushWindow];
  139.     [gameWindow flushWindow];
  140.  
  141.     /*-----------------------------------------------------------------------
  142.      *     Initialize the stockCardPileView to have a shuffled deck.
  143.      *---------------------------------------------------------------------*/
  144.     [stockCardPile freeCards];
  145.     if (redeal)
  146.     {
  147.         [[stockCardPile addDeck] shuffle];
  148.     
  149.     // make a copy of the CardPile for restart option
  150.     if (!prevDeck)
  151.     {
  152.         prevDeck = [[CardPile allocFromZone:[self zone]]
  153.                                initForCardSize:cardSize];
  154.     }
  155.     else
  156.     {
  157.         [prevDeck freeCards];
  158.         [prevDeck setCardSize:cardSize];
  159.     }
  160.     [prevDeck addCopyOfPile:stockCardPile];
  161.     }
  162.     else
  163.     {
  164.         if (prevDeck)
  165.     {
  166.         // copy the saved deck back to the game deck
  167.         [prevDeck setCardSize:cardSize];
  168.         [stockCardPile addCopyOfPile:prevDeck];
  169.     }
  170.     else
  171.     {
  172.         // this shouldn't happen, but just in case...
  173.             [[[stockCardPile freeCards] addDeck] shuffle];
  174.     }
  175.     }
  176.  
  177.     /*-----------------------------------------------------------------------
  178.      * Initialize the other piles as empty.
  179.      *---------------------------------------------------------------------*/
  180.  
  181.     [[wasteCardPileView cardPile] freeCards];
  182.     [[discardCardPileViewL cardPile] freeCards];
  183.     [[discardCardPileViewR cardPile] freeCards];
  184.     [wasteCardPileView display];
  185.     [discardCardPileViewL display];
  186.     [discardCardPileViewR display];    
  187.     
  188.     /*-----------------------------------------------------------------------
  189.      *    Remove the remaining gameCardPileViews from the view
  190.      *    hierarchy so they can be put back in correct order.
  191.      *      As cards are removed from the Pyramid during game play, the
  192.      *    Pyramid cardPileViews are removed from the view hierarchy to
  193.      *    allow access to the piles underneath.
  194.      *---------------------------------------------------------------------*/
  195.  
  196.     for (pileIndex = 0; pileIndex < 28; pileIndex++)
  197.     {
  198.     if ([gameCardPiles[pileIndex] superview])
  199.         [gameCardPiles[pileIndex] removeFromSuperview];
  200.     }
  201.  
  202.     /*-----------------------------------------------------------------------
  203.      * Set the attributes of the pyramid cardpiles
  204.      *---------------------------------------------------------------------*/
  205.  
  206.     for (pileIndex = 0; pileIndex < 28; pileIndex++)
  207.     {
  208.         [gameCardPiles[pileIndex] setDelegate:gameDelegate];
  209.         [gameCardPiles[pileIndex] setBackgroundColor:desktopColor];
  210.     [gameCardPiles[pileIndex] setCardSize:cardSize];
  211.     [gameCardPiles[pileIndex] setDelegate:gameDelegate];
  212.     [gameCardPiles[pileIndex] setDrawOutline:NO];
  213.     [gameCardPiles[pileIndex] resetBacking:self];
  214.     if (pileIndex > 0) [gameCardPiles[pileIndex] setCoversOthers:YES];
  215.     }
  216.  
  217.  
  218.     /*-----------------------------------------------------------------------
  219.      *    Initialize and deal cards to the 28 "game piles"
  220.      *---------------------------------------------------------------------*/
  221.  
  222.     for (pileIndex = 0; pileIndex < 28; pileIndex++)
  223.     {
  224.         id userPile, tempCard;
  225.     
  226.         /*-------------------------------------------------------------------
  227.          *    Reinsert the game pile view in the proper hierachy.
  228.          *    The views are unlinked during game play.
  229.      *-----------------------------------------------------------------*/
  230.  
  231.     [[stockCardPileView superview] addSubview:gameCardPiles[pileIndex]];
  232.  
  233.     /*-------------------------------------------------------------------
  234.          *    Deal the cards.
  235.      *-----------------------------------------------------------------*/
  236.     
  237.     userPile = [gameCardPiles[pileIndex] cardPile];
  238.     [userPile freeCards];
  239.     tempCard = [stockCardPile cardAt:CS_TOP];
  240.     [stockCardPile removeCard:tempCard];
  241.     [userPile insertCard:tempCard at:CS_TOP];
  242.     [[userPile cardAt:CS_TOP] flip];
  243.     }
  244.     
  245.     /*-----------------------------------------------------------------------
  246.      * Update all views, then display the window.
  247.      *---------------------------------------------------------------------*/
  248.     [gameWindow display];
  249.     [gameWindow makeKeyAndOrderFront:self];
  250.  
  251.     return self;
  252. }
  253.  
  254.  
  255. /*---------------------------------------------------------------------------
  256. |
  257. |    - endGame:sender
  258. |
  259. |    returns:  (id) self
  260. |
  261. |----------------------------------------------------------------------------
  262. |
  263. |    End the game in progress.  Discard the game window.
  264. |            
  265. \----------------------------------------------------------------------------*/
  266.  
  267. - endGame:sender
  268. {
  269.     if (gameInProgress) 
  270.     {
  271.         [self determineScore];
  272.     gameInProgress = NO;
  273.     }
  274.  
  275.     // close the game window
  276.     [super endGame:sender];
  277.  
  278.     return self;
  279. }
  280.  
  281. /*---------------------------------------------------------------------------
  282. |
  283. |    - win
  284. |
  285. |     returns: (id) self
  286. |
  287. |----------------------------------------------------------------------------
  288. |
  289. |    Called when the game has been won.  This is where you can insert fancy
  290. |    winning routines, or just call the default (boring) routine.
  291. |
  292. \----------------------------------------------------------------------------*/
  293.  
  294. - win
  295. {
  296.     [super win];  // replace this with something wonderful
  297.     return self;
  298. }
  299.  
  300.  
  301. /*---------------------------------------------------------------------------
  302. |
  303. |    - checkForWin
  304. |
  305. |    returns: (id) self
  306. |
  307. |----------------------------------------------------------------------------
  308. |
  309. |    Called to check the state of the game.  Always override (unless your
  310. |    game is impossible to win).  This is ugly because it handles winning
  311. |    and keeping track of the score.
  312. |
  313. \----------------------------------------------------------------------------*/
  314.  
  315. - checkForWin
  316. {
  317.     int i, j;
  318.     int total;
  319.     id viewList = [[gameWindow contentView] subviews];
  320.     BOOL didMatch;
  321.     
  322.     total = [viewList count];
  323.  
  324.     /*-----------------------------------------------------------------------
  325.      *
  326.      *    Points for clearing the pyramid...
  327.      *
  328.      *---------------------------------------------------------------------*/
  329.     for (j = 0, didMatch = NO; j < total && !pyramidEmpty && !didMatch; j++)
  330.     {
  331.         id theView = [viewList objectAt:j];
  332.     
  333.         for (i = 0; i < 28 && !didMatch; i++)
  334.     {
  335.         if (theView == gameCardPiles[i]) 
  336.             didMatch = YES;
  337.     }
  338.     }
  339.     if (!didMatch && !pyramidEmpty)
  340.     {
  341.     switch ([self dealCount])
  342.     {
  343.     case 1:
  344.         [prefs setPyramidScore:[prefs pyramidScore] + 50];
  345.         break;
  346.     case 2:
  347.         [prefs setPyramidScore:[prefs pyramidScore] + 35];
  348.         break;
  349.     case 3:
  350.         [prefs setPyramidScore:[prefs pyramidScore] + 20];
  351.         break;
  352.     default:
  353.         break;
  354.     }
  355.     pyramidEmpty = YES;
  356.     }
  357.  
  358.  
  359.     /*-----------------------------------------------------------------------
  360.      *
  361.      *    Cleared everything; you win.
  362.      *
  363.      *---------------------------------------------------------------------*/
  364.  
  365.     if ([[discardCardPileViewL cardPile] cardCount] +
  366.         [[discardCardPileViewR cardPile] cardCount] == 52)
  367.     {
  368.         [self win];
  369.     gameInProgress = NO;
  370.     return self;
  371.     }
  372.     
  373.     /*-----------------------------------------------------------------------
  374.      *
  375.      *    If the stock pile is empty and we have used both redeals AND the
  376.      *    pyramid is empty, then it's time to count the remaining cards.
  377.      *
  378.      *---------------------------------------------------------------------*/
  379.     if (pyramidEmpty && [[stockCardPileView cardPile] cardCount] == 0 &&
  380.             [self dealCount] == 3)
  381.     {
  382.         [self determineScore];
  383.     gameInProgress = NO;
  384.     return self;
  385.     }
  386.     
  387.     gameInProgress = YES;
  388.     return self;
  389. }
  390.  
  391.  
  392. /*---------------------------------------------------------------------------
  393. |
  394. |    - (int)dealCount
  395. |
  396. |    returns: (int) the number of deals so far (1, 2, 3, ...)
  397. |
  398. |----------------------------------------------------------------------------
  399. |
  400. |    The deal count is incremented everytime the deck is flipped.
  401. |
  402. \----------------------------------------------------------------------------*/
  403.  
  404. - (int)dealCount
  405. {
  406.     return dealCount;
  407. }
  408.  
  409.  
  410. /*---------------------------------------------------------------------------
  411. |
  412. |    - setDealCount:(int)count
  413. |
  414. |    returns: (id) self
  415. |
  416. |----------------------------------------------------------------------------
  417. |
  418. |    Set the deal count.  This is the number of passes through the stock.
  419. \----------------------------------------------------------------------------*/
  420.  
  421. - setDealCount:(int)count
  422. {
  423.     dealCount = count;
  424.     return self;
  425. }
  426.  
  427.  
  428. /*---------------------------------------------------------------------------
  429. |
  430. |    - incDealCount
  431. |
  432. |    returns: (id) self
  433. |
  434. |----------------------------------------------------------------------------
  435. |
  436. |    Add one to the deal count.
  437. |
  438. \----------------------------------------------------------------------------*/
  439.  
  440. - incDealCount
  441. {
  442.     dealCount++;
  443.     return self;
  444. }
  445.  
  446.  
  447. /*---------------------------------------------------------------------------
  448. |
  449. |    - determineScore
  450. |
  451. |    returns: (id) self
  452. |
  453. |----------------------------------------------------------------------------
  454. |
  455. |    Subtract the remaining cards from the current score.
  456. |
  457. \----------------------------------------------------------------------------*/
  458.  
  459. - determineScore
  460. {
  461.     int i;
  462.     int total = 0;
  463.     
  464.     for (i = 0; i < 28; i++)
  465.     {
  466.         total += [[gameCardPiles[i] cardPile] cardCount];
  467.     }
  468.     total += [[stockCardPileView cardPile] cardCount];
  469.     total += [[wasteCardPileView cardPile] cardCount];
  470.  
  471.     [prefs setPyramidScore:[prefs pyramidScore] - total];
  472.  
  473.     return self;
  474. }
  475.  
  476.  
  477. @end
  478.  
  479.